package com.shuiyun.jtt.entity.bo;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.shuiyun.jtt.message.jt808.T0100;
import java.nio.charset.Charset;

import com.shuiyun.jtt.message.jt808.T0102;
import com.shuiyun.jtt.utils.Bcd;
import com.shuiyun.jtt.utils.EncryptUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.time.LocalDate;
import java.util.Base64;

/**
 * @author shuiyun
 * @program gateway
 * @description 设备信息
 * @date 2022-04-21 18:41
 **/
@Slf4j
@Data
public class DeviceInfo {

    /**
     * 签发日期
     */
    private LocalDate issuedAt;
    /**
     * 有效期 （日）
     */
    private Integer validAt;
    /**
     * 卡号
     */
    private String cardNumber;
    /**
     * 车牌颜色
     */
    private Integer plateColor;
    /**
     * 车牌号
     */
    private String plateNo;
    /**
     * 设备ID
     */
    private String deviceId;


    public DeviceInfo() {
        issuedAt = LocalDate.now();
        validAt = 7;
    }

    public DeviceInfo(T0100 request) {
        issuedAt = LocalDate.now();
        validAt = 7;
        plateNo = request.getPlateNo();
        plateColor = request.getPlateColor();
        deviceId = request.getDeviceId();
        cardNumber = request.getHeader().getMobileNo();
    }


    private static DeviceInfo formBytes(byte[] bytes) {
        try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
             DataInputStream dis = new DataInputStream(bis)) {

            DeviceInfo result = new DeviceInfo();
            byte[] temp;
            dis.read(temp = new byte[3]);
            result.setIssuedAt(LocalDate.now());
            result.setValidAt(7);
            int len = dis.readUnsignedByte();
            dis.read(temp = new byte[len]);
            result.setDeviceId(new String(temp, Charset.forName("GBK")));

            return result;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 数据实体转字节流
     * @param deviceToken 认证信息
     * @author shuiyun
     * @date 2022/4/21 21:43
     * @return 转换好的字节流
     */
    private static byte[] toBytes(DeviceInfo deviceToken) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream(32);
             DataOutputStream dos = new DataOutputStream(bos)) {

            dos.write(Bcd.from(deviceToken.getIssuedAt()));
            dos.writeByte(deviceToken.getValidAt());
            // todo 缓存中的数据没有deviceId数据
            String deviceId = deviceToken.getDeviceId();
            byte[] bytes = ObjectUtil.isEmpty(deviceId) ? new byte[]{0} : deviceId.getBytes(Charset.forName("GBK"));
            dos.writeByte(bytes.length);
            dos.write(bytes);

            return bos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据设备信息获取token
     * @param deviceToken 认证的设备信息
     * @author shuiyun
     * @date 2022/4/21 21:44
     * @return token 信息
     */
    public static String getToken(DeviceInfo deviceToken){
        byte[] bytes = EncryptUtils.encrypt(toBytes(deviceToken));
        return Base64.getEncoder().encodeToString(bytes);
    }

    public static DeviceInfo auth(T0102 request){
        if (StrUtil.isBlank(request.getToken())){
            return null;
        }
        byte[] bytes = Base64.getDecoder().decode(request.getToken());
        bytes = EncryptUtils.decrypt(bytes);
        DeviceInfo device = DeviceInfo.formBytes(bytes);
        LocalDate expiresAt = device.getIssuedAt().plusDays(device.getValidAt());
        if (expiresAt.isBefore(LocalDate.now())){
            // TODO 暂时不对过期时间校验
            log.error("鉴权失败，过期的token:{}",request.getToken());
        }
        return device;
    }
}
